<?php
App::uses('AppHelper', 'View/Helper');
App::import('Vendor', 'Util');

class CombinatorHelper extends AppHelper
{
    public $vue = null;

    public $libs = array(
        'css' => array(),
        'js' => array()
    );
    public $inline_code = array(
        'css' => array(),
        'js' => array()
    );

    public $base_path = null;
    public $cache_path = null;
    public $extra_path = null;

    public $options = array(
        'css' => array(
            'path' => '/css',
            'cache_path' => '/css',
            'enable_compression' => false
        ),
        'js' => array(
            'path' => '/js',
            'cache_path' => '/js',
            'enable_compression' => false
        )
    );

    public function __construct(View $view, $options = array())
    {
        parent::__construct($view, $options);

        $this->options['js'] = !empty($options['js']) ? am($this->options['js'], $options['js']) : $this->options['js'];
        $this->options['css'] = !empty($options['css']) ? am($this->options['css'], $options['css']) : $this->options['css'];
        $this->vue = ClassRegistry::getObject('view');

        $this->options['js']['path'] = $this->cleanPath($this->options['js']['path']);
        $this->options['js']['cache_path'] = $this->cleanPath($this->options['js']['cache_path']);
        $this->options['css']['path'] = $this->cleanPath($this->options['css']['path']);
        $this->options['css']['cache_path'] = $this->cleanPath($this->options['css']['cache_path']);

        $this->base_path['js'] = WWW_ROOT . $this->options['js']['path'];
        $this->cache_path['js'] = WWW_ROOT . $this->options['js']['cache_path'];
        $this->base_path['css'] = WWW_ROOT . $this->options['css']['path'];
        $this->cache_path['css'] = WWW_ROOT . $this->options['css']['cache_path'];

        if (Configure::read('App.baseUrl')) {
            $this->extra_path = 'app/webroot/';
        } else {
            $this->extra_path = '';
        }
    }

    public function scripts($type, $file_name = null, $async = false)
    {
        $file_name = !is_null($file_name) ? trim($file_name) : '';

        switch ($type) {
            case 'js':
                $cachefile_js = $this->generateFilename('js', $file_name);
                return $this->getJsHtml($cachefile_js, $async);

            case 'css':
                $cachefile_css = $this->generateFilename('css', $file_name);
                return $this->getCssHtml($cachefile_css);

            default:
                $cachefile_js = $this->generateFilename('js', $file_name);
                $output_js = $this->getJsHtml($cachefile_js, $async);
                if ($output_js) {
                }

                $cachefile_css = $this->generateFilename('css', $file_name);
                $output_css = $this->getCssHtml($cachefile_css);
                return $output_css . "\n" . $cachefile_js;
        }
    }

    private function generateFilename($type, $file_name)
    {
        $file_name = trim($file_name);
        $this->libs[$type] = array_unique($this->libs[$type]);

        if (!file_exists($this->cache_path[$type])) {
            @mkdir($this->cache_path[$type]);
        }

        foreach ($this->libs[$type] as $key => $lib) {
            $lib = $this->cleanLibList($lib, $type);
            $this->libs[$type][$key] = $lib;
        }

        if ($file_name == '') {
            $has = Util::hashId(crc32(serialize($this->libs[$type])));
        } else {
            $hash = $file_name;
        }

        return 'asset_' . $hash . '.' . $type;
    }

    private function getJsHtml($cachefile, $async)
    {
        if (false === file_exists($this->cache_path['js'] . '/' . $cachefile)) {
            $file_content = '';
            foreach ($this->libs['js'] as $lib) {
                $file_content .= trim(file_get_contents($this->base_path['js'] . '/' . $lib));
            }

            if ($this->options['js']['enable_compression']) {
                App::import('Vendor', 'Combinator.jsmin/jsmin');
                $file_content = trim(JSMin::minify($file_content));
            }

            if (!empty($this->inline_code['js'])) {
                foreach ($this->inline_code['js'] as $inlineJs) {
                    $file_content .= $inlineJs . "\n";
                }
            }

            $file_content = trim($file_content);
            $fp = fopen($this->cache_path['js'] . '/' . $cachefile, 'wb');
            if ($fp) {
                @fwrite($fp, $file_content);
                @fclose($fp);
            }
        }

        return '<script type="text/javascript" ' . ($async == true ? 'async ' : '') . 'src="' . $this->url('/' . $this->extra_path . $this->options['js']['cache_path'] . '/' . $cachefile) . '?' . Configure::read('asset_version') . '"></script>';
    }

    private function getCssHtml($cachefile)
    {
        if (false === file_exists($this->cache_path['css'] . '/' . $cachefile)) {
            $file_content = '';
            foreach ($this->libs['css'] as $lib) {
                $file_content .= trim(file_get_contents($this->base_path['css'] . '/' . $lib));
            }

            if (!empty($this->inline_code['css'])) {
                foreach ($this->inline_code['css'] as $inlineCss) {
                    $file_content .= $inlineCss . "\n";
                }
            }

            if ($this->options['css']['enable_compression']) {
                App::import('Vendor', 'Combinator.cssmin', array('file' => 'cssmin' . DS . 'cssmin.php'));
                $css_minifier = new CssMinifier($file_content);
                $file_content = $css_minifier->getMinified();
            }

            $file_content = trim($file_content);
            $fp = fopen($this->cache_path['css'] . '/' . $cachefile, 'wb');
            if ($fp) {
                @fwrite($fp, $file_content);
                @fclose($fp);
            }
        }

        return '<link type="text/css" rel="stylesheet" href="' . $this->url('/' . $this->extra_path . $this->options['css']['cache_path'] . '/' . $cachefile) . '?' . Configure::read('asset_version') . '" />';
    }

    public function addLibs($type, $libs)
    {
        switch ($type) {
            case 'js':
            case 'css':
                if (is_array($libs)) {
                    foreach ($libs as $lib) {
                        $this->libs[$type][] = $lib;
                    }
                } else {
                    $this->libs[$type][] = $libs;
                }

                break;
        }
    }

    public function resetLibList($type)
    {
        switch ($type) {
            case 'js':
            case 'css':
                $this->libs[$type] = array();
                break;
        }
    }

    public function addInlineCode($type, $codes)
    {
        switch ($type) {
            case 'js':
            case 'css':
                if (is_array($codes)) {
                    foreach ($codes as $code) {
                        $this->inline_code[$type][] = $code;
                    }
                } else {
                    $this->inline_code[$type][] = $codes;
                }

                break;
        }
    }

    private function cleanLibList($filename, $type)
    {
        if (strpos($filename, '?') === false) {
            if (strpos($filename, '.' . $type) === false) {
                $filename .= '.' . $type;
            }
        }

        return $filename;
    }

    private function cleanPath($path)
    {
        $len = strlen($path);
        if (strrpos($path, '/') == ($len - 1)) {
            $path = substr($path, 0, $len - 1);
        }

        if (strpos($path, '/') == '0') {
            $path = substr($path, 1, $len);
        }

        return $path;
    }
}